package com.hulk.boot.common.util;

import com.google.common.collect.Lists;

import org.dozer.DozerBeanMapper;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 简单封装Dozer, 实现深度转换Bean<->Bean的Mapper.实现:
 * 
 * 1. 持有Mapper的单例. 2. 泛型返回值转换. 3. 批量转换Collection中的所有对象. 4.
 * 区分创建新的B对象与将对象A值复制到已存在的B对象两种函数.
 * 
 * Author: cmt
 */
public class BeanMapper {

	/**
	 * 持有Dozer单例, 避免重复创建DozerMapper消耗资源.
	 */
	private static DozerBeanMapper dozer = new DozerBeanMapper();

	private BeanMapper() {
	}

	/**
	 * 基于Dozer转换对象的类型.
	 */
	public static <T> T map(Object source, Class<T> destinationClass) {
		return dozer.map(source, destinationClass);
	}

	/**
	 * 基于Dozer转换对象的类型.
	 */
	public static <T> T mapNotNull(Object source, Class<T> destinationClass) {
		if (source != null) {
			return dozer.map(source, destinationClass);
		}
		return null;
	}

	/**
	 * 基于Dozer转换Collection中对象的类型.
	 */
	@SuppressWarnings("rawtypes")
	public static <T> List<T> mapList(Collection sourceList,
			Class<T> destinationClass) {
		List<T> destinationList = Lists.newArrayList();
		for (Object sourceObject : sourceList) {
			T destinationObject = dozer.map(sourceObject, destinationClass);
			destinationList.add(destinationObject);

		}
		return destinationList;
	}

	/**
	 * 基于Dozer将对象A的值拷贝到对象B中.
	 */
	public static void copy(Object source, Object destinationObject) {
		dozer.map(source, destinationObject);
	}

	public static void copyNotNull(Object source, Object destinationObject) {
		if (source != null && destinationObject != null) {
			dozer.map(source, destinationObject);
		} else {
			destinationObject = null;
		}
	}

	/**
	 * map转换为对象
	 * 
	 * @param type
	 * @param map
	 * @return
	 * @throws IntrospectionException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	@SuppressWarnings("rawtypes")
	public static Object convert2Entity(Map map, Class clazz) {

		// class clazz = object.getClass();
		// 获取类属性
		BeanInfo beanInfo = null;
		// 创建对象
		Object obj = null;
		try {
			beanInfo = Introspector.getBeanInfo(clazz);
			obj = clazz.newInstance();
		} catch (InstantiationException | IllegalAccessException
				| IntrospectionException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			throw new RuntimeException(e1);
		}
		// 给 JavaBean对象的属性赋值
		PropertyDescriptor[] propertyDescriptors = beanInfo
				.getPropertyDescriptors();
		for (int i = 0; i < propertyDescriptors.length; i++) {
			PropertyDescriptor descriptor = propertyDescriptors[i];
			String propertyName = descriptor.getName();
			if (map != null && map.containsKey(propertyName)) {
				Object value = map.get(propertyName);
				Object[] args = new Object[1];
				args[0] = value;
				try {
					descriptor.getWriteMethod().invoke(obj, args);
				} catch (IllegalAccessException | IllegalArgumentException
						| InvocationTargetException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				}
			}
		}
		return obj;

	}

	public static final String[] excludeMethods = new String[] { "hashCode",
			"getClass", "wait", "equals", "notify", "notifyAll", "toString" };

	/**
	 * 将Entity转换为Map<String,String>
	 * 
	 * @param targetObj
	 * @return
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	public static Map<String, String> convert2Map(Object targetObj,
			String[] excludeNamesIn) throws Exception {
		if (targetObj == null) {
			return null;
		}

		Map<String, String> result = new HashMap<String, String>();
		Method methods[] = targetObj.getClass().getMethods();
		for (Method method : methods) {
			String methodName = method.getName();
			String properity;
			String value = null;

			if (methodName.indexOf("set") == 0) {
				continue;
			}

			boolean isExclude = false;
			for (String exclude : excludeMethods) {
				if (exclude.equals(methodName)) {
					isExclude = true;
					break;
				}
			}

			if (excludeNamesIn != null) {
				for (String exclude : excludeNamesIn) {
					if (exclude.equals(methodName)) {
						isExclude = true;
						break;
					}
				}
			}

			if (isExclude == true) {
				continue;
			}

			Object valueObj = method.invoke(targetObj, "");
			if (valueObj != null) {
				value = String.valueOf(valueObj);
				properity = methodName.substring(3);
				properity = properity.substring(0, 1).toLowerCase()
						+ properity.substring(1);
				result.put(properity, value);
			}
		}

		return result;
	}

	/**
	 * 打印对象的值
	 * 
	 * @param obj
	 */
	public static void printBeanValues(Object obj) {
		Class<?> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			try {
				System.out.println(field.getName() + "=" + field.get(obj));
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	public static void printBeanValues2(Object obj) {
		Class<?> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		System.out.println();
		for (Field field : fields) {
			field.setAccessible(true);
			try {
				System.out.print(field.getName() + "=" + field.get(obj) + ", ");
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		System.out.println();
	}

}